package com.zndroid.netmonitor.monitor.impl;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.telephony.PhoneStateListener;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;

import com.zndroid.netmonitor.NetType;
import com.zndroid.netmonitor.monitor.IMPL;
import com.zndroid.netmonitor.monitor.INetChangeCallBack;
import com.zndroid.netmonitor.monitor.Util;

import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * API >=21 采用广播的形式实现
 * */
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class MonitorImplAPI21 extends ConnectivityManager.NetworkCallback implements IMPL {
    protected WeakReference<Context> context;
    protected final Util util;

    protected final @NonNull
    INetChangeCallBack netChangeCallBack;
    private final @NonNull NetStatusBroadcastReceiver netStatusBroadcastReceiver;

    protected PhoneStateListener mPhoneStateListener;

    protected final AtomicBoolean isReg = new AtomicBoolean(false);

    public MonitorImplAPI21(@NonNull INetChangeCallBack netChangeCallBack) {
        this.netChangeCallBack = netChangeCallBack;
        util = new Util();
        netStatusBroadcastReceiver = new MonitorImplAPI21.NetStatusBroadcastReceiver();
    }

    @Override
    public void startMonitor(@NonNull Context context) {
        if (isReg.get()) return;//防止重复调用

        Log.d(TAG, "MonitorImplAPI21 impl...");

        this.context = new WeakReference<>(context);

        if (!util.isNetworkAvailable(context))
            netChangeCallBack.onNetConnected(false, NetType.NET_NONE);

        NetworkRequest.Builder builder = new NetworkRequest.Builder();
        NetworkRequest request = builder.build();
        ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (manager != null)
            manager.registerNetworkCallback(request, this);
        else
            netChangeCallBack.onNetConnected(false, NetType.NET_NONE);

        monitorSignal(context);

        isReg.set(true);
    }

    @Override
    public void stopMonitor() {
        if (context.get() != null && isReg.getAndSet(false)) {
            Log.d(TAG, "NetWorkMonitor will be stop...");

            ConnectivityManager manager = (ConnectivityManager) context.get().getSystemService(Context.CONNECTIVITY_SERVICE);
            assert manager != null;
            manager.unregisterNetworkCallback(this);

            stopMonitorSignal(context.get());
        }
    }

    //信号强度监听
    protected void monitorSignal(@NonNull Context context) {
        monitorWifiSignal(context);
        monitorPhoneSignal(context);
    }

    //停止信号强度监听
    protected void stopMonitorSignal(@NonNull Context context) {
        stopMonitorWifiSignal(context);
        stopMonitorPhoneSignal(context);
    }

    protected void monitorPhoneSignal(@NonNull Context context) {
        mPhoneStateListener = new PhoneStateListener() {
            @Override
            public void onSignalStrengthsChanged(SignalStrength signalStrength) {
                super.onSignalStrengthsChanged(signalStrength);
                if (util.getNetType(context).contentEquals(NetType.NET_WIFI)) return;

                Method method;
                int level = 0;

                try {
                    method = SignalStrength.class.getMethod("getLevel");
                    method.setAccessible(true);
                    level = (int) method.invoke(signalStrength);
                } catch (Exception e) {
                    //nothing
                }
                netChangeCallBack.onNetChanged(util.isNetworkAvailable(context), util.getNetType(context), level);
            }
        };


        if (util.hasSimCard(context)) {
            TelephonyManager telephonyManager = (TelephonyManager) this.context.get().getSystemService(Context.TELEPHONY_SERVICE);
            assert telephonyManager != null;
            telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
        }
    }

    protected void monitorWifiSignal(@NonNull Context context) {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        intentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
        context.registerReceiver(netStatusBroadcastReceiver, intentFilter);
    }

    protected void stopMonitorPhoneSignal(@NonNull Context context) {
        if (util.hasSimCard(context)) {
            TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            assert telephonyManager != null;
            telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
        }
    }

    protected void stopMonitorWifiSignal(@NonNull Context context) {
        context.unregisterReceiver(netStatusBroadcastReceiver);
    }

    @Override
    public void onAvailable(@NonNull Network network) {
        super.onAvailable(network);
        netChangeCallBack.onNetConnected(util.isNetworkAvailable(context.get()), util.getNetType(context.get()));
    }

    @Override
    public void onLost(@NonNull Network network) {
        super.onLost(network);
        netChangeCallBack.onNetConnected(util.isNetworkAvailable(context.get()), util.getNetType(context.get()));
    }

    /**
     * 会回调多次，对于常用逻辑来讲无需监听，如果要实时监听，可以使用{@link INetChangeCallBack#onNetChanged(boolean, String, int)}回调进行监听
     * */
    @Override
    public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
        super.onCapabilitiesChanged(network, networkCapabilities);
//        netChangeCallBack.onNetConnected(util.isNetworkAvailable(context.get()), util.getNetType(context.get()));
    }

    class NetStatusBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (util.getNetType(context).equalsIgnoreCase(NetType.NET_WIFI)) {
                if (util.isWifiConnected(context)) {
                    WifiManager wifiManager = (WifiManager)context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
                    int si = WifiManager.calculateSignalLevel(wifiManager.getConnectionInfo().getRssi(), 5);
                    netChangeCallBack.onNetChanged(util.isNetworkAvailable(context), util.getNetType(context), si);
                } else {
                    netChangeCallBack.onNetChanged(util.isNetworkAvailable(context), util.getNetType(context), 0);
                }
            }
        }
    }

}
